import asyncio
import json
import shutil

from fastapi import FastAPI, UploadFile, File, Form
from fastapi import Query
from typing import Optional
from contextlib import asynccontextmanager
import os

from interview_voice_project.common import generate_markdown, get_logger
from interview_voice_project.common import get_project_root, get_file_extension
from interview_voice_project.common import get_current_time, get_datetime_from_str
from datetime import datetime
from interview_voice_project.__002__db_helper_parse import my_db_helper
from interview_voice_project.__002__db_helper_parse.model.tb_scoring_template import TbScoringTemplate
from interview_voice_project.__001__langgraph_more_node.langgraph_agent import interview_voice_analyse

logger = get_logger(__name__)

@asynccontextmanager
async def lifespan(app: FastAPI):
    try:
        from interview_voice_project.common import my_voice_model
        from interview_voice_project.common import my_llm
        logger.info("app_startup: asr_llm_imported")
    except Exception as e:
        logger.error(f"app_startup_err: {str(e)}")
    yield
    logger.info("app_shutdown")

app = FastAPI(lifespan=lifespan)

UPLOAD_DIR = get_project_root.joinpath("uploaded_files")  # Directory to store the uploaded files
if not os.path.exists(UPLOAD_DIR):
    os.makedirs(UPLOAD_DIR)

@app.get("/interview_records")
async def get_interview_records(
    page: int = Query(1, ge=1),
    page_size: int = Query(10, ge=1, le=100),
    status: Optional[int] = Query(None),
    company: Optional[str] = Query(None),
    subject: Optional[str] = Query(None),
):
    try:
        filters = {}
        if status is not None:
            filters["processing_status"] = status
        if company:
            filters["company_name"] = company
        if subject:
            filters["subject"] = subject
        page_items, total = my_db_helper.get_interview_records_paginated(filters or None, exclude_fields=["markdown_text", "update_time"], page=page, page_size=page_size)
        logger.info(f"get_interview_records_total：{total}")
        return {"data": page_items, "total": total, "page": page, "page_size": page_size}
    except Exception as e:
        logger.error(f"get_interview_records_errmsg：{str(e)}")
        return {"error": str(e)}


@app.get("/get_interview_records_by_record_id")
async def get_interview_records_by_record_id(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        logger.info(f"get_interview_records_by_record_id-data_dict：{data_dict}")

        id = data_dict.get("record_id", "")
        records = my_db_helper.get_all_interview_records({"id": id}, exclude_fields=["update_time"])
        data_dict = records[0]
        md_text = data_dict.get("markdown_text")
        if not md_text:
            detail_list = my_db_helper.get_analysis_details_by_record_id(interview_record_analysis_id=id)
            markdown_text = generate_markdown(records, detail_list)
            data_dict["markdown_text"] = markdown_text
            if markdown_text:
                my_db_helper.update_interview_record(id, {"markdown_text": markdown_text})
        return {"data": data_dict}
    except Exception as e:
        logger.error(f"get_interview_records_by_record_id_errmsg：{str(e)}")
        return {"error": str(e)}


@app.get("/health")
async def health():
    try:
        from interview_voice_project.common import my_voice_model
        from interview_voice_project.common import config_ini
        from interview_voice_project.common import my_llm
        device = getattr(my_voice_model, "device", None)
        llm_model = getattr(config_ini.LLM, "DEEPSEEK_MODEL", None)
        llm_base = getattr(config_ini.LLM, "DEEPSEEK_BASE_URL", None)
        return {"asr_ready": True, "asr_device": str(device), "llm_ready": True, "llm_model": llm_model, "llm_base_url": llm_base}
    except Exception as e:
        logger.error(f"health_errmsg：{str(e)}")
        return {"error": str(e)}


@app.post("/add_interview_record")
async def add_interview_record(
        json_data_str: str = Form(...),  # 获取 JSON 字符串数据
        file: UploadFile = File(...),  # 获取上传的文件
):
    try:
        # 解析 JSON 数据
        data_dict = json.loads(json_data_str)
        logger.info(f"add_interview_record-data_dict：{data_dict}")

        name = data_dict.get("name", "")
        company = data_dict.get("company", "")
        subject = data_dict.get("subject", "")
        scoring_template_key = data_dict.get("scoring_template_key")
        if not scoring_template_key:
            default_tpl = my_db_helper.get_default_scoring_template()
            scoring_template_key = (default_tpl or {}).get("template_key") or "技术岗"
        interview_date_str = data_dict.get("interview_date_str", "")

        extension = get_file_extension(file.filename)
        save_file_name = f"{get_current_time()}_{name}_{company}{extension}"
        # 保存上传的文件到服务器
        relative_path = os.path.join("uploaded_files", save_file_name)
        file_location = os.path.join(UPLOAD_DIR, save_file_name)
        with open(file_location, "wb") as f:
            shutil.copyfileobj(file.file, f)

        my_db_helper.add_interview_record(name=name, company_name=company, subject=subject,
                                          interview_time=get_datetime_from_str(interview_date_str),
                                          recording_url=relative_path,
                                          scoring_template_key=scoring_template_key)

    except Exception as e:
        import traceback
        traceback.print_exc()
        logger.error(f"add_interview_record_errmsg：{str(e)}")
        return {"error": str(e)}


@app.post("/start_analysis_local")
async def start_analysis_local(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        logger.info(f"start_analysis_local-data_dict：{data_dict}")

        name = data_dict.get("name", "")
        company = data_dict.get("company", "")
        subject = data_dict.get("subject", "")
        scoring_template_key = data_dict.get("scoring_template_key")
        if not scoring_template_key:
            default_tpl = my_db_helper.get_default_scoring_template()
            scoring_template_key = (default_tpl or {}).get("template_key") or "技术岗"
        interview_date_str = data_dict.get("interview_date_str", "")
        file_relative_path = data_dict.get("file_relative_path", "")

        record_id = my_db_helper.add_interview_record(name=name, company_name=company, subject=subject,
                                                      interview_time=get_datetime_from_str(interview_date_str),
                                                      recording_url=file_relative_path,
                                                      scoring_template_key=scoring_template_key)
        # 标记处理中并记录开始时间
        my_db_helper.update_interview_record(record_id, {"processing_status": 1, "process_start_time": datetime.now()})

        info = {
            "name": name,
            "company": company,
            "subject": subject,
            "interview_date_str": interview_date_str
        }

        async def run_once():
            try:
                await interview_voice_analyse(get_project_root.joinpath(file_relative_path), record_id, info)
                my_db_helper.update_interview_record(record_id, {"processing_status": 2, "process_end_time": datetime.now()})
            except Exception as e:
                logger.error(f"start_analysis_local_err_run：{str(e)}")
                my_db_helper.update_interview_record(record_id, {"processing_status": 3, "processing_tips": str(e), "process_end_time": datetime.now()})

        asyncio.create_task(run_once())
        return {"record_id": record_id}
    except Exception as e:
        logger.error(f"start_analysis_local_errmsg：{str(e)}")
        return {"error": str(e)}


@app.post("/retry_markdown_generation")
async def retry_markdown_generation(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        record_id = data_dict.get("record_id")
        if not record_id:
            return {"error": "record_id不能为空"}
        records = my_db_helper.get_all_interview_records({"id": record_id}, exclude_fields=["update_time"])
        if not records:
            return {"error": "记录不存在"}
        detail_list = my_db_helper.get_analysis_details_by_record_id(interview_record_analysis_id=record_id)
        markdown_text = generate_markdown(records, detail_list)
        if markdown_text:
            my_db_helper.update_interview_record(record_id, {"markdown_text": markdown_text})
            return {"data": "ok"}
        return {"error": "生成失败"}
    except Exception as e:
        logger.error(f"retry_markdown_generation_errmsg：{str(e)}")
        return {"error": str(e)}


@app.post("/delete_recording")
async def delete_recording(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        record_id = data_dict.get("record_id")
        if not record_id:
            return {"error": "record_id不能为空"}

        records = my_db_helper.get_all_interview_records({"id": record_id})
        if not records:
            return {"error": "记录不存在"}

        record = records[0]
        status = record.get("processing_status", 0)
        if status == 1:
            return {"error": "处理中记录不可删除录音"}

        rel_path = record.get("recording_url", "")
        if rel_path:
            file_location = os.path.join(get_project_root, rel_path)
            file_location_str = str(file_location)
            upload_dir_str = str(UPLOAD_DIR)
            if not file_location_str.startswith(upload_dir_str):
                return {"error": "非法路径，拒绝删除"}
            if os.path.exists(file_location_str):
                os.remove(file_location_str)

        my_db_helper.update_interview_record(record_id, {"recording_url": ""})
        return {"data": "ok"}
    except Exception as e:
        import traceback
        traceback.print_exc()
        logger.error(f"delete_recording_errmsg：{str(e)}")
        return {"error": str(e)}


@app.post("/delete_record")
async def delete_record(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        record_id = data_dict.get("record_id")
        if not record_id:
            return {"error": "record_id不能为空"}

        records = my_db_helper.get_all_interview_records({"id": record_id})
        if not records:
            return {"error": "记录不存在"}

        record = records[0]
        status = record.get("processing_status", 0)
        if status == 1:
            return {"error": "处理中记录不可删除"}

        rel_path = record.get("recording_url", "")
        if rel_path:
            file_location = os.path.join(get_project_root, rel_path)
            file_location_str = str(file_location)
            upload_dir_str = str(UPLOAD_DIR)
            if file_location_str.startswith(upload_dir_str) and os.path.exists(file_location_str):
                os.remove(file_location_str)

        # 删除数据库记录（含详情）
        ok = my_db_helper.delete_record_by_id(record_id)
        if ok:
            return {"data": "ok"}
        return {"error": "删除失败"}
    except Exception as e:
        import traceback
        traceback.print_exc()
        logger.error(f"delete_record_errmsg：{str(e)}")
        return {"error": str(e)}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8001)
@app.post("/scoring_template/add")
async def add_scoring_template(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        tpl_key = data_dict.get("template_key")
        weights_json = data_dict.get("weights_json")
        description = data_dict.get("description")
        default_flag = int(data_dict.get("default_flag", 0))
        if not tpl_key or not weights_json:
            return {"error": "template_key 与 weights_json 必填"}
        tpl_id = my_db_helper.add_scoring_template(tpl_key, weights_json, description, default_flag)
        return {"data": tpl_id}
    except Exception as e:
        logger.error(f"add_scoring_template_errmsg：{str(e)}")
        return {"error": str(e)}

@app.get("/scoring_template/list")
async def list_scoring_template(template_key: Optional[str] = Query(None)):
    try:
        filters = {"template_key": template_key} if template_key else None
        items = my_db_helper.get_scoring_templates(filters)
        return {"data": items}
    except Exception as e:
        logger.error(f"list_scoring_template_errmsg：{str(e)}")
        return {"error": str(e)}

@app.post("/scoring_template/update")
async def update_scoring_template(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        tpl_id = int(data_dict.get("id", 0))
        update_fields = data_dict.get("update_fields", {})
        if not tpl_id or not isinstance(update_fields, dict):
            return {"error": "id 与 update_fields 必填"}
        ok = my_db_helper.update_scoring_template(tpl_id, update_fields)
        return {"data": "ok" if ok else "fail"}
    except Exception as e:
        logger.error(f"update_scoring_template_errmsg：{str(e)}")
        return {"error": str(e)}

@app.post("/scoring_template/delete")
async def delete_scoring_template(json_data_str: str = Form(...)):
    try:
        data_dict = json.loads(json_data_str)
        tpl_id = int(data_dict.get("id", 0))
        if not tpl_id:
            return {"error": "id 必填"}
        ok = my_db_helper.delete_scoring_template(tpl_id)
        return {"data": "ok" if ok else "fail"}
    except Exception as e:
        logger.error(f"delete_scoring_template_errmsg：{str(e)}")
        return {"error": str(e)}
